package site.teamo.biu.net.client.service.impl;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import site.teamo.biu.net.client.configuration.ClientConfiguration;
import site.teamo.biu.net.client.controller.model.server_management.Server;
import site.teamo.biu.net.client.entity.ServerDO;
import site.teamo.biu.net.client.mapper.ServerMapper;
import site.teamo.biu.net.client.service.ServerManagementService;
import site.teamo.biu.net.common.constant.HttpHeader;
import site.teamo.biu.net.common.exception.BiuNetBusinessException;
import site.teamo.biu.net.common.report.ReportRequest;
import site.teamo.biu.net.common.report.ReportResponse;
import site.teamo.biu.net.common.web.constant.ResponseCode;
import site.teamo.biu.net.common.web.mapper.SystemConfigMapper;
import site.teamo.biu.tool.core.model.BiuJSONResult;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author haocongshun
 * @date 2023/06/07 16:01:54
 */
@Service
public class ServerManagementServiceImpl implements ServerManagementService {

    @Resource
    private ServerMapper serverMapper;

    private Cache<String, Server> cache = CacheUtil.newTimedCache(10000);

    @Resource
    private SystemConfigMapper systemConfigMapper;

    @Override
    public List<Server> queryServers() {
        List<ServerDO> serverDOS = serverMapper.selectList(new QueryWrapper<>());
        List<Server> result = new ArrayList<>();
        for (ServerDO serverDO : serverDOS) {
            Server server = cache.get(serverDO.getId(), false);
            if (server == null) {
                server = getServer(serverDO);
                cache.put(serverDO.getId(), server);
            }
            result.add(server);
        }
        return result;
    }

    @Override
    public boolean access(String accessUrl) {
        String clientId = ClientConfiguration.CLIENT_ID.getContent(systemConfigMapper);
        Map<String, String> data = JSON.<BiuJSONResult<Map<String, String>>>parseObject(
                HttpUtil.get(accessUrl + "&id=" + clientId),
                new TypeReference<BiuJSONResult<Map<String, String>>>() {
                }).getData();
        return serverMapper.insert(new ServerDO()
                .setReportUrl(data.get("url"))
                .setToken(data.get("token"))) > 0;
    }

    @Override
    public boolean delete(String id) {
        if (StrUtil.equals(ClientConfiguration.HTTP_HTTPS_PROXY_SERVICE_USED_SERVER_ID.getContent(systemConfigMapper), id)) {
            throw new BiuNetBusinessException(ResponseCode.BUSINESS_ERROR, "该服务节点被Http&Https代理服务使用中，无法删除");
        }
        return serverMapper.deleteById(id) > 0;
    }

    @Override
    public Server queryServer(String id) {
        if (StrUtil.isBlank(id)) {
            return null;
        }
        ServerDO serverDO = serverMapper.selectById(id);
        if (serverDO == null) {
            return null;
        }
        return getServer(serverDO);
    }

    private Server getServer(ServerDO serverDO) {
        ReportRequest request = new ReportRequest();
        request.setId(ClientConfiguration.CLIENT_ID.getContent(systemConfigMapper));
        request.setHttpHttpsProxyOnline(ClientConfiguration.HTTP_HTTPS_PROXY_SERVICE_USED_SERVER_ID.getContent(systemConfigMapper).equals(serverDO.getId()));
        long start = System.currentTimeMillis();
        HttpRequest post = HttpUtil.createPost(serverDO.getReportUrl());
        post.header(HttpHeader.ACCESS_TOKEN, serverDO.getToken());
        post.body(JSON.toJSONString(request));
        post.timeout(10000);
        try (HttpResponse response = post.execute()) {
            BiuJSONResult<ReportResponse> result = JSON.parseObject(response.body(), new TypeReference<BiuJSONResult<ReportResponse>>() {
            });
            if (result.getData() == null) {
                return new Server().fromServerDO(serverDO);
            }
            long ping = System.currentTimeMillis() - start;
            return new Server()
                    .fromReportResponse(result.getData())
                    .setId(serverDO.getId())
                    .setPing(ping)
                    .setAccessTime(serverDO.getCreateTime().getTime());
        } catch (Exception e) {
            return new Server().fromServerDO(serverDO);
        }
    }
}
